home *** CD-ROM | disk | FTP | other *** search
- /* $change:Modifications to fix errors in handling of some PCX files.$ */
- /*
- ** $id: ssvcid pcx.c 1.0 08/03/92 10:01 am$
- ** Support functions for reading in PCX files and creating a DIB.
- **
- ** (C) 1992-3 Larry Widing
- */
- #include <windows.h>
- #include <stdlib.h>
- #include <mem.h>
- #include "bitmaps.h"
- #include "pcx.h"
-
- #define SEEK_SET 0
- #define SEEK_END 2
-
- /*
- ** PCX File Header Structure
- */
- typedef struct pcxhdr {
- BYTE manufacturer; /* 10 == ZSoft */
- BYTE version; /* 0 = Paintbrush 2.5
- ** 2 = 2.8 with palette
- ** 3 = 2.8 without palette
- ** 4 = PC Paintbrush for Windows
- ** 5 = Version 3.0+ and Publishers Paintbrush */
- BYTE encode; /* 1 = PCX RLE */
- BYTE bitsPerPixel; /* 1, 2, 4, or 8 */
- short minX; /* Window dimensions */
- short minY;
- short maxX;
- short maxY;
- short horzDpi; /* Horizontal dots per inch */
- short vertDpi; /* Vertical dots per inch */
- RGBTRIPLE pal1[16]; /* palette */
- BYTE junk;
- BYTE planes; /* number of color planes */
- short bytesPerLine; /* number of bytes per scanline */
- short paltype; /* 1 = Color, 2 = GrayScale */
- short hScreenSize; /* Horizontal Screen Size */
- short vScreenSize; /* Vertical Screen Size */
- BYTE filler[54];
- } PCXHDR;
-
- /*
- ** Note: Version 5 images may contain a 256 color palette at the end of the
- ** file. Check for it by checking if the byte 769 bytes before the end of
- ** the file is 12.
- */
- typedef struct pcxpal256 {
- BYTE flag; /* 12 if it exists */
- RGBTRIPLE pal2[256]; /* palette entries */
- } PCXPAL256;
-
- /*
- ** Bit masks for planar decoding
- */
- static BYTE LowMasks[4] = { 0x01, 0x02, 0x04, 0x08 };
- static BYTE HighMasks[4] = { 0x10, 0x20, 0x40, 0x80 };
-
- /*
- ** Default 16 color VGA palette
- */
- static RGBTRIPLE DefaultPalette[16] = {
- { 0, 0, 0 },
- { 0, 0, 255 },
- { 0, 255, 0 },
- { 0, 255, 255 },
- { 255, 0, 0 },
- { 255, 0, 255 },
- { 255, 255, 0 },
- { 255, 255, 255 },
- { 85, 85, 255 },
- { 85, 85, 85 },
- { 0, 170, 0 },
- { 170, 0, 0 },
- { 85, 255, 255 },
- { 255, 85, 255 },
- { 255, 255, 85 },
- { 255, 255, 255 }
- };
-
- /*
- ** static int -1 if an error occured, 0 otherwise
- ** PcxNextByte(
- ** BYTE *byte, pointer to resultant value
- ** int *count, pointer to repeat count, 1 if no repeat
- ** HANDLE fileHandle); handle of file being read
- **
- ** Get the next byte from the PCX file, and determine if it is a repeat
- ** string or a literal byte.
- **
- ** Modification History:
- ** 07/31/92 LCW Commented
- */
- static int
- PcxNextByte(BYTE *byte, int *count, int fileHandle)
- {
- BYTE value;
-
- *count = 1;
- if (_lread(fileHandle, (LPSTR)&value, sizeof(value)) != sizeof(value))
- {
- return -1;
- }
-
- /*
- ** Check for a repeat count, indicated by the two high bits being set
- */
- if (0x00c0 == (0x00c0 & value))
- {
- *count = 0x3f & value;
- if (_lread(fileHandle, (LPSTR)&value, sizeof(value)) != sizeof(value))
- {
- return -1;
- }
- }
- *byte = value;
-
- return 0;
- }
-
- /*
- ** HDIB handle of resultant DIB, NULL on error
- ** ReadPcxFile(const char *filename); name of file to load
- **
- ** Read a image in from a ZSoft PCX file, creating a Windows compatible
- ** DIB, and returning its handle to the caller.
- **
- ** Modification History:
- ** 07/31/92 LCW Commented
- */
- HDIB
- ReadPcxFile(const char *filename)
- {
- HDIB dib = (HDIB)NULL, dib2;
- HFILE fileHandle;
- LPBITMAPINFOHEADER bmi;
- RGBQUAD FAR *rgb;
- RGBTRIPLE *palPtr;
- int i, j, colors, count, row, col, maxrow, plane;
- BYTE chr, mask, bit, highbit;
- DWORD dibSize;
- PCXHDR pcxHeader;
- PCXPAL256 pcxPal;
- OFSTRUCT ofs;
- long l, imageBytes, bytesPerScanLine, bytesPerImageLine;
- unsigned char HUGE *pixels;
- unsigned char HUGE *pPix;
-
- /*
- ** Open the file
- */
- fileHandle = OpenFile(filename, (LPOFSTRUCT)&ofs, OF_READ);
- if (fileHandle == -1)
- {
- return (HDIB)NULL;
- }
-
- /*
- ** Read in the header information, and verify it
- */
- _llseek(fileHandle, 0L, SEEK_SET);
- if (sizeof(pcxHeader) != _lread(fileHandle, (LPSTR)&pcxHeader, sizeof(pcxHeader)))
- {
- _lclose(fileHandle);
- return (HDIB)NULL;
- }
-
- if (pcxHeader.manufacturer != 10)
- {
- _lclose(fileHandle);
- return (HDIB)NULL;
- }
-
- if (pcxHeader.bitsPerPixel * pcxHeader.planes == 1)
- {
- colors = 2;
- }
- else
- {
- colors = 16;
- }
-
- /*
- ** Set palPtr to point to the palette for this image
- */
- palPtr = pcxHeader.pal1;
- if (pcxHeader.version == 5)
- {
- _llseek(fileHandle, -769L, SEEK_END);
- if (sizeof(pcxPal) == _lread(fileHandle, (LPSTR)&pcxPal, sizeof(pcxPal))
- && pcxPal.flag == 12)
- {
- colors = 256;
- palPtr = pcxPal.pal2;
- }
- }
-
- /*
- ** Create the bitmap header
- */
- dib = GlobalAlloc(GHND,
- (LONG)sizeof(BITMAPINFOHEADER) + colors * sizeof(RGBQUAD));
- if (dib == (HDIB)NULL)
- {
- _lclose(fileHandle);
- return (HDIB)NULL;
- }
-
- bmi = (LPBITMAPINFOHEADER)GlobalLock(dib);
- bmi->biSize = sizeof(BITMAPINFOHEADER);
- bmi->biWidth = 1 + pcxHeader.maxX - pcxHeader.minX;
- bmi->biHeight = 1 + pcxHeader.maxY - pcxHeader.minY;
- bmi->biPlanes = 1;
- bmi->biBitCount = pcxHeader.bitsPerPixel * pcxHeader.planes;
- if (bmi->biBitCount == 3)
- bmi->biBitCount = 4;
- bmi->biCompression = BI_RGB;
- bmi->biSizeImage = ((DWORD)bmi->biBitCount * (DWORD)bmi->biWidth) / 8;
- /*
- ** NOTE: remember that each line of a DIB must align on a DWORD boundry
- */
- bmi->biSizeImage += (bmi->biSizeImage & 3) ? 4 - (bmi->biSizeImage & 3) : 0;
- bytesPerImageLine = bmi->biSizeImage;
- bmi->biSizeImage *= (DWORD)bmi->biHeight;
- bmi->biXPelsPerMeter = 0;
- bmi->biYPelsPerMeter = 0;
- bmi->biClrUsed = colors;
- bmi->biClrImportant = colors;
-
- /*
- ** Fill in intensities for all palette entry colors. Note the order
- ** change between PCX and DIB.
- */
- rgb = (RGBQUAD FAR *)((LPSTR)bmi + (int)bmi->biSize);
- for (i = 0 ; i < colors ; ++i)
- {
- rgb[i].rgbRed = palPtr[i].rgbtBlue;
- rgb[i].rgbGreen = palPtr[i].rgbtGreen;
- rgb[i].rgbBlue = palPtr[i].rgbtRed;
- rgb[i].rgbReserved = 0;
- }
-
- /*
- ** Not all PCX files have a valid palette
- */
- if (pcxHeader.version == 2 || pcxHeader.version >= 4)
- {
- for (i = 0 ; i < colors ; ++i)
- {
- if (rgb[i].rgbRed != 0 || rgb[i].rgbGreen != 0 || rgb[i].rgbBlue != 0)
- {
- break;
- }
- }
- }
- else
- {
- i = colors;
- }
-
- if (i == colors)
- {
- if (colors <= 16)
- {
- /*
- ** Use default 16 color palette
- */
- for (i = 0 ; i < colors ; ++i)
- {
- rgb[i].rgbRed = DefaultPalette[i].rgbtRed;
- rgb[i].rgbGreen = DefaultPalette[i].rgbtGreen;
- rgb[i].rgbBlue = DefaultPalette[i].rgbtBlue;
- rgb[i].rgbReserved = 0;
- }
- }
- else
- {
- /*
- ** Use default Windows Palette
- */
- bmi->biClrUsed = bmi->biClrImportant = 0;
- }
- }
-
- dibSize = bmi->biSize + (DWORD)bmi->biClrUsed * sizeof(RGBQUAD) + bmi->biSizeImage;
- dib2 = GlobalAlloc(GHND, dibSize);
- if (dib2 == (HWND)NULL)
- {
- _lclose(fileHandle);
- GlobalUnlock(dib);
- GlobalFree(dib);
- return (HDIB)NULL;
- }
- pixels = (unsigned char HUGE *)GlobalLock(dib2);
- _fmemcpy(pixels, bmi, (size_t)(dibSize - bmi->biSizeImage));
- GlobalUnlock(dib);
- GlobalFree(dib);
- dib = dib2;
- bmi = (LPBITMAPINFOHEADER)pixels;
- pixels += dibSize - bmi->biSizeImage;
-
- /*
- ** Now to do the actual image reading
- */
- _llseek(fileHandle, (long)sizeof(pcxHeader), SEEK_SET);
- bytesPerScanLine = (long)pcxHeader.bytesPerLine * (long)pcxHeader.planes;
- imageBytes = bytesPerScanLine * bmi->biHeight;
-
- row = col = 0;
- maxrow = (int)bmi->biHeight - 1;
- for (l = 0 ; l < imageBytes ; )
- {
- if (-1 == PcxNextByte(&chr, &count, fileHandle))
- {
- goto read_exit;
- }
-
- for (i = 0 ; i < count ; ++i)
- {
- /*
- ** Locate the correct row and column
- */
- col = (int) ((l + i) % bytesPerScanLine);
- row = (int) ((l + i) / bytesPerScanLine);
-
- if (row > maxrow || row < 0)
- {
- goto read_exit;
- }
-
- if (pcxHeader.planes == 3 || pcxHeader.planes == 4)
- {
- plane = col / pcxHeader.bytesPerLine;
- if (plane < 0 || plane >= pcxHeader.planes)
- {
- goto read_exit;
- }
- col = col % pcxHeader.bytesPerLine;
- bit = LowMasks[plane];
- highbit = HighMasks[plane];
- pPix = pixels + col * 4L + (long)(maxrow - row) * bytesPerImageLine;
- for (j = 0 ; j < 8 ; j += 2)
- {
- mask = 0x80 >> j;
- if (chr & mask)
- {
- *pPix |= highbit;
- }
-
- mask >>= 1;
- if (chr & mask)
- {
- *pPix |= bit;
- }
- ++pPix;
- }
- }
- else
- {
- pPix = pixels + col + (maxrow - row) * bytesPerImageLine;
- *pPix = chr;
- }
- }
- l += count;
- }
-
- _lclose(fileHandle);
- return dib;
-
- read_exit:
- _lclose(fileHandle);
- GlobalUnlock(dib);
- GlobalFree(dib);
- dib = (HDIB)NULL;
-
- return dib;
- }
-
- /*
- ** Modification History
- ** ====================
- **
- ** $lgb$
- ** 08/03/92 Larry Widing Initial Version.
- ** $lge$
- */
-
-